home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / devel / lang / lisp / stk-3.002 / stk-3 / STk-3.1 / Contrib / Process / process.c next >
Encoding:
C/C++ Source or Header  |  1994-06-11  |  13.8 KB  |  629 lines

  1. #include    "stk.h"
  2. #include    <fcntl.h>
  3. #include    <errno.h>
  4. #include    <sys/param.h>
  5. #include    <sys/wait.h>
  6. #include  <unistd.h>
  7. #include    <signal.h>
  8.  
  9.  
  10. #define MAX_PROC_NUM                            256 /*enough eh?*/
  11. #define    MAX_ARGS_NO                256
  12.  
  13. #define    NO_REDIRECTION               0
  14. #define    REDIRECTION_BY_FILE        1
  15. #define    REDIRECTION_BY_STREAM    2
  16.  
  17.  
  18. /******** SIGUSR1 handler *******/
  19. static void su1_handler(){
  20. /*  printf("SIGUSR1 arrived\n"); */
  21. }
  22. /*********************************/
  23.  
  24. /**** Registering processes ****/
  25. static SCM proc_arr[MAX_PROC_NUM];
  26.  
  27.  
  28. static init_proc_table(){
  29.   int i;
  30.   for(i = 0; i<MAX_PROC_NUM; i++)
  31.     proc_arr[i] = ntruth;
  32. }
  33.  
  34. static int find_process(SCM prc){
  35.   int i;
  36.   int ret = -1;
  37.   for(i = 0; i<MAX_PROC_NUM; i++){
  38.     if(prc==proc_arr[i]){
  39.       ret = i;
  40.       break;
  41.     }
  42.   }
  43.   return ret;
  44. }
  45.  
  46. static int reg_process(SCM prc){
  47.   int i;
  48.   /* find slot */
  49.   i = find_process(ntruth);
  50.   if(i<0){
  51.     gc_for_newcell();
  52.     i = find_process(ntruth);
  53.   }
  54.   if (i < 0){
  55.     err("Too many processes", NIL);
  56.     return -1;
  57.   }
  58.   proc_arr[i] = prc;
  59.   return 0;
  60. }
  61.  
  62. static 
  63. int find_slot(){
  64.   int i;
  65.   /* find slot */
  66.   i = find_process(ntruth);
  67.   if(i<0){
  68.     gc_for_newcell();
  69.     i = find_process(ntruth);
  70.   }
  71.   if (i < 0){
  72.     err("Too many processes", NIL);
  73.     return -1;
  74.   }
  75.   return i;
  76. }
  77.        
  78. static int remove_process(SCM prc){
  79.   int i;
  80.   /* find slot */
  81.   i = find_process(prc);
  82.   if(i<0){
  83.     err("unregistered process", prc);
  84.     return -1;
  85.   }
  86.   proc_arr[i] = ntruth;
  87.   return 0;
  88. }
  89.  
  90.  
  91.  
  92.  
  93.  
  94. /**** gc-helpers *****/
  95. static void free_process( SCM process );
  96. static void mark_process( SCM process );
  97.  
  98.  
  99.  
  100. static int tc_process;
  101.  
  102. static extended_scheme_type process_type = {
  103.   "process",        /* name */
  104.   0,            /* is_procp */
  105.   mark_process,        /* gc_mark_fct */
  106.   free_process,            /* gc_sweep_fct */
  107.   NULL,            /* apply_fct */
  108.   NULL            /* display_fct */
  109. };
  110.  
  111.  
  112.  
  113. struct process_info {
  114.   int pid;                          /* pid */
  115.   char  *commandLine;        /* Cmdline used to start process */
  116.   char  redirection[3];        /* Types of redirection           */
  117.   struct obj   *stream[3];
  118. };
  119.  
  120. #define PROCESS(x) ((struct process_info *)(x->storage_as.extension.data))
  121. #define PROCESSP(x) (TYPEP (x, tc_process))
  122. #define NPROCESSP(x) (NTYPEP (x, tc_process))
  123. #define PROCPID(x)  PROCESS(x)->pid
  124.  
  125.  
  126. extern char **sys_errlist;
  127.  
  128. static char    *stdStreams[3] = {
  129.     "standard input",    "standard output",    "standard error",
  130. };
  131.  
  132. static char *strName[3] = {
  133.     "stdin", "stdout", "stderr",
  134. };
  135.  
  136. static PRIMITIVE
  137. fork_process( SCM command, SCM args, SCM redirection, int run_async );
  138.  
  139. PRIMITIVE
  140. run_process( SCM command, SCM args, SCM redirection ) {
  141.   return fork_process(command, args, redirection, 1);
  142. }
  143.  
  144. PRIMITIVE
  145. run_sync( SCM command, SCM args, SCM redirection ) {
  146.   return fork_process(command, args, redirection, 0);
  147. }
  148.  
  149. static PRIMITIVE
  150. fork_process( SCM command, SCM args, SCM redirection, int run_async ) {
  151.   SCM        pinfo, arg, pnames, ptypes;
  152.   char    *argv[MAX_ARGS_NO], msg[256], *files[3];
  153.   int        argc, pid, i;
  154.   long    flag;
  155.   int        pipes[3][2];
  156.   int        redirectionType[3];
  157.   struct    process_info    *info;
  158.   void *old_chld_sig_action;
  159.   int svMask, usermask; int ok;
  160.   int svMask1, mypid;  
  161.         usermask = (sigmask(SIGUSR1));
  162.  
  163.   /* Checking arguments and creating UNIX-style */
  164.   /* arguments list */
  165.   
  166.   if( NSTRINGP( command ) )
  167.     err("run-process: bad program name", command);
  168.   i = find_slot();  
  169.   if( i < 0)
  170.     return ntruth;
  171.   
  172.   NEWCELL(pinfo, tc_process);
  173.   proc_arr[i] = pinfo;
  174.  
  175.   info    = (struct process_info *) malloc( sizeof( struct process_info ) );
  176.   PROCESS(pinfo) = info;
  177.   /*
  178.    *
  179.    *    Initializing info structure
  180.    *
  181.    */
  182.   
  183.   info->commandLine        = strdup(CHARS( command ) );
  184.  
  185.   for( i = 0; i < 3; i++ ) {
  186.     info->redirection[i]  = NO_REDIRECTION;
  187.     info->stream[i]      = NIL;
  188.   }
  189.   
  190.   argv[0]    = CHARS( command );
  191.   
  192.   for( argc = 1; argc < MAX_ARGS_NO && NNULLP( args ); ++argc ) {
  193.     if( NCONSP( args ) )
  194.       err("run-process: bad arguments list", args);
  195.  
  196.     arg    = CAR( args );
  197.     args  = CDR( args );
  198.  
  199.     if( NSTRINGP( arg ) ) {
  200.       /* In future, may be I implement conversion from */
  201.       /* non-string argument to the string, but today */
  202.       /* I don't want to do that :) */
  203.       
  204.       err("run-process: bad argument -- must be string", arg);
  205.     }
  206.  
  207.     argv[argc]    = CHARS( arg );
  208.   }
  209.  
  210.   if( argc == MAX_ARGS_NO )
  211.     err("run-process: too many arguments (limit is 256)", args);
  212.  
  213.   argv[argc]    = NULL;
  214.  
  215.  
  216.   /* Parsing redirection's list and creating communication */
  217.  
  218.   if( NNULLP( redirection ) ) {
  219.  
  220.     for( i = 0; i < 3; ++i ) {
  221.       if( NCONSP( redirection ) )
  222.         err("run-process: wrong redirection's list", redirection);
  223.       
  224.       if( STRINGP( CAR( redirection ) ) ) {
  225.  
  226.         info->redirection[i]  = REDIRECTION_BY_FILE;
  227.         info->stream[i]      = string_copy( CAR( redirection ) );
  228.         
  229.         /* redirectionType[i]    = REDIRECTION_BY_FILE;
  230.        files[i]        = CHARS( CAR( redirection ) ); */
  231.         
  232.         pipes[i][0]        = open(CHARS( CAR( redirection ) ),
  233.                   i == 0 ? O_RDONLY : O_WRONLY);
  234.         if( pipes[i][0] < 0 ) {
  235.           sprintf(msg, "run-process: can't redirect %s to file %s",
  236.           stdStreams[i], CHARS( CAR( redirection ) ));
  237.           
  238.           err( msg, NIL );
  239.         }
  240.  
  241.         redirection  = CDR( redirection );
  242.         continue;
  243.       }
  244.  
  245.       if( BOOLEANP( CAR( redirection ) ) ) {
  246.  
  247.         if( CAR( redirection ) == truth ) {
  248.           if( pipe( pipes[i] ) < 0 ) {
  249.             
  250.             sprintf(msg, "run-process: can't create stream for %s\n",
  251.             stdStreams[i]
  252.  
  253.             );
  254.             perror("Process");
  255.             err( msg, NIL );
  256.           }
  257.           
  258.           /* redirectionType[i]  = REDIRECTION_BY_STREAM; */
  259.           
  260.           info->redirection[i]  = REDIRECTION_BY_STREAM;
  261.         }
  262.  
  263.         redirection    = CDR( redirection );
  264.         continue;
  265.       }
  266.  
  267.       err("run-process: bad redirection type", CAR( redirection ));
  268.     }
  269.   }
  270.  
  271.     
  272.   /* set handler to catch SIGUSR1 */
  273.   signal(SIGUSR1,su1_handler); 
  274.  
  275.   /* block user1 signal till parent will be ready */
  276.   svMask1 = sigblock(usermask);
  277.   mypid = getpid();
  278.  
  279.   /* Now, forking and catching the errors */
  280.   pid    = fork();
  281.  
  282.   if( pid < 0 ) {
  283.     char  msg[256];
  284.  
  285.     sprintf(msg,
  286.         "run-process: can't create child process because of (see stderr)"
  287.         );
  288.     perror("CHILD process");
  289.     err( msg, NIL );
  290.   }
  291.  
  292.   /* Processing child's behavior */
  293.  
  294.   if( pid == 0 ) {
  295.     if(run_async){
  296.       svMask = sigblock(usermask);
  297.       signal(SIGUSR1,su1_handler); 
  298.       /* send notification to parent that I'm ready */
  299.       ok = kill(mypid,SIGUSR1);
  300.       if(ok < 0) perror( "Sending to parent");
  301.       sigpause(0); 
  302.       sigsetmask(svMask);
  303. /*
  304.  *      fprintf(stderr, "Mask: %x\n", usermask);
  305.  *      fprintf(stderr, "Child continues...");
  306.  *      perror("Child:");
  307.  */
  308.  
  309.       setsid();
  310.     }
  311.       
  312.     for( i = 0; i < 3; ++i ) {
  313.       switch( info->redirection[i] ) {
  314.   
  315.       case REDIRECTION_BY_FILE:
  316.     dup2( pipes[i][0], i );
  317.     close( pipes[i][0] );
  318.     break;
  319.   
  320.       case REDIRECTION_BY_STREAM:
  321.     dup2( pipes[i][ i == 0 ? 0 : 1], i );
  322.     close( pipes[i][0] );
  323.     close( pipes[i][1] );
  324.     break;
  325.   
  326.       default:
  327.     break;
  328.       }
  329.     }
  330.     
  331.     for( i = 3; i < NOFILE; ++i )
  332.       close( i );
  333.     
  334.     
  335.     /*  And then, EXEC'ing...  */
  336.     
  337.     execvp( argv[0], argv );
  338.     
  339.     /* Unfortunatelly, we can't exec this process -- but */
  340.     /* we can't tell 'bout this fact to our daddy. :( */
  341.     
  342.     fprintf(stderr, "Can't exec!");
  343.     exit( 1 );
  344.   }
  345.   
  346.   /*  Ok, guys, we are still in the parent process. Making redirection */
  347.   /*  and filling-up PROCESS structure */
  348.   PROCPID( pinfo )  = pid;
  349.   if(!run_async) waitpid(pid);
  350.   else {
  351.     for( i = 0; i < 3; ++i ) {
  352.       switch( info->redirection[i] ) {
  353.       case REDIRECTION_BY_FILE:
  354.     close( pipes[i][0] );
  355.     break;
  356.     
  357.       case REDIRECTION_BY_STREAM:
  358.     close( pipes[i][ i == 0 ? 0 : 1 ] );
  359.     
  360.     flag  = no_interrupt(1);
  361.     
  362.     NEWCELL( info->stream[i], i == 0 ? tc_oport : tc_iport );
  363.     
  364.     if( (info->stream[i]->storage_as.port.f =
  365.          fdopen( pipes[i][ i == 0 ? 1 : 0],
  366.             i == 0 ? "w" : "r" )) == NULL )
  367.       err("process-input: can't FDOPEN stream", pinfo);
  368.     
  369.     sprintf(msg, "*%s-%d*", strName[i], pid);
  370.     
  371.     info->stream[i]->storage_as.port.name  = must_malloc( strlen( msg ) + 1 );
  372.     strcpy( info->stream[i]->storage_as.port.name, msg );  
  373.     
  374.     no_interrupt( flag );
  375.     break;
  376.     
  377.       default:
  378.     break;
  379.       }
  380.     }
  381.     /** all house keeping is done... notyfy child to go ***/
  382. #if 1
  383.       sigpause(0); /* wait for child notification */
  384.       sigsetmask(svMask1); 
  385.     /* notify child */
  386.     ok = kill(pid,SIGUSR1);
  387.     if(ok < 0) perror("Parent sigusr");
  388. /*    else fprintf(stderr, "Parent sending SIGUSR1 to %d\n",pid); */
  389. #endif
  390.   }
  391.   PROCESS( pinfo )  = info;
  392.   return  pinfo;
  393. }
  394.  
  395.  
  396. /*** INTERFACE ****/
  397.  
  398. PRIMITIVE
  399.   processp( SCM process ) {
  400.        return PROCESSP( process ) ? truth : ntruth;
  401.      }
  402.  
  403.  
  404. PRIMITIVE
  405. process_alivep( SCM process ) {
  406.  
  407.   if( NPROCESSP( process ) )
  408.     err("process-alive?: wrong argument type", process);
  409.  
  410.   return  kill( PROCPID( process ), 0 ) == 0 ? truth : ntruth;
  411. }
  412.  
  413. PRIMITIVE
  414. process_pid( SCM process ) {
  415.  
  416.   if( NPROCESSP( process ) )
  417.     err("process-pid: wrong argument type", process);
  418.  
  419.   return  makeinteger( PROCPID( process ) );
  420. }
  421.  
  422. static char  *rtFile    = "*File*";
  423. static char *rtStream  = "*Stream*";
  424. static char  *rtNone    = "*None*";
  425.  
  426. static PRIMITIVE
  427. get_internal_redirection( SCM process, int i ) {
  428.   SCM    rType, rName;
  429.   struct process_info  *info;
  430.   
  431.   if( NPROCESSP( process ) )
  432.     err("process-stream-type: wrong argument type", process);
  433.  
  434.   info  = PROCESS( process );
  435.   
  436.   switch( info->redirection[i] ) {
  437.  
  438.     case REDIRECTION_BY_FILE:
  439.     rType  = makestrg( strlen( rtFile ), rtFile );
  440.     rName  = string_copy( info->stream[i] );
  441.     break;
  442.  
  443.     case NO_REDIRECTION:
  444.     rType  = makestrg( strlen( rtNone ), rtNone );
  445.     rName  = NIL;
  446.     break;
  447.  
  448.     default: /* REDIRECTION_BY_STREAM */
  449.     rType  = makestrg( strlen( rtStream ), rtStream );
  450.     rName  = makestrg( strlen( stdStreams[i] ), stdStreams[i] );
  451.     break;
  452.   }
  453.  
  454.   return  cons( rType, rName );
  455. }
  456.  
  457.  
  458. /*** enumerate ***/
  459. PRIMITIVE 
  460. process_list(){
  461.   int i;
  462.   SCM lst = NIL;
  463.   for(i = 0; i<MAX_PROC_NUM; i++)
  464.     if(proc_arr[i] != ntruth)
  465.       lst = cons(proc_arr[i],lst);
  466.   return lst;
  467. }
  468.   
  469.  
  470.     
  471. PRIMITIVE
  472. process_input_info( SCM process ) {
  473.  
  474.   return  get_internal_redirection( process, 0 );
  475. }
  476.  
  477. PRIMITIVE
  478. process_output_info( SCM process ) {
  479.   
  480.   return  get_internal_redirection( process, 1 );
  481. }
  482.  
  483. PRIMITIVE
  484. process_error_info( SCM process ) {
  485.   
  486.   return  get_internal_redirection( process, 2 );
  487. }
  488.  
  489. PRIMITIVE
  490. process_command( SCM process ) {
  491.   struct process_info *info;
  492.   
  493.   if( NPROCESSP( process ) )
  494.     err("process-command: wrong argument type", process);
  495.  
  496.   info  = PROCESS( process );
  497.   
  498.   return  makestrg( strlen( info->commandLine ), info->commandLine );
  499. }
  500.  
  501.  
  502. /*
  503.  * Creating and returning ports to opened streams
  504.  */
  505.  
  506. PRIMITIVE
  507. process_input( SCM process ) {
  508.   struct process_info  *info;
  509.   
  510.   if( NPROCESSP( process ) )
  511.     err("process-input: wrong argument type", process);
  512.   
  513.   info  = PROCESS( process );
  514.   
  515.   if( info->redirection[0] != REDIRECTION_BY_STREAM ) {
  516.     return  NIL;
  517.   }
  518.  
  519.   return  info->stream[0];
  520. }
  521.  
  522. PRIMITIVE
  523. process_output( SCM process ) {
  524.   struct process_info  *info;
  525.   
  526.   if( NPROCESSP( process ) )
  527.     err("process-input: wrong argument type", process);
  528.   
  529.   info  = PROCESS( process );
  530.   
  531.   if( info->redirection[1] != REDIRECTION_BY_STREAM ) {
  532.     return  NIL;
  533.   }
  534.  
  535.   return  info->stream[1];
  536. }
  537.  
  538. PRIMITIVE
  539. process_error( SCM process ) {
  540.   struct process_info  *info;
  541.   
  542.   if( NPROCESSP( process ) )
  543.     err("process-input: wrong argument type", process);
  544.   
  545.   info  = PROCESS( process );
  546.   
  547.   if( info->redirection[2] != REDIRECTION_BY_STREAM ) {
  548.     return  NIL;
  549.   }
  550.  
  551.   return  info->stream[2];
  552. }
  553.  
  554.  
  555. void 
  556. mark_process( SCM process ){
  557.   struct process_info *info;
  558.   int i;
  559.   info = PROCESS(process);
  560.   for(i=0; i<3 ; i++)
  561.    gc_mark(info->stream[i]);
  562. }
  563.  
  564.  
  565. void
  566. free_process( SCM process ) {
  567.   int    i;
  568.   struct process_info *info;
  569.   info  = PROCESS( process );
  570.   i = remove_process(process);
  571.   if(i < 0)
  572.     err("cannot unregister process", process);
  573.   if( info->commandLine )
  574.     free( info->commandLine );
  575.   
  576.   for( i = 0; i < 3; ++i ) {
  577.     if( info->redirection[i] == REDIRECTION_BY_STREAM && info->stream[i] != NIL ) {
  578.       freeport( info->stream[i] );
  579.     }
  580.   }
  581.   free(info); /* A.T. ++ */
  582. }
  583.  
  584.  
  585. PRIMITIVE
  586. process_kill( SCM process ) {
  587.   struct process_info *info;  
  588.   int i;
  589.   if( NPROCESSP( process ) )
  590.     err("process-kill: wrong argument", process);
  591.   
  592.   info  = PROCESS( process );  
  593. #if 1
  594.   for( i = 0; i < 3; ++i ) {
  595.     if( info->redirection[i] == REDIRECTION_BY_STREAM && 
  596.        info->stream[i] != NIL ) {
  597.       freeport( info->stream[i] );
  598.       info->stream[i]=NIL;
  599.     }
  600.   }
  601. #endif
  602.   kill( PROCPID( process ), 15 );
  603.   return  truth;
  604. }
  605.  
  606.  
  607. /******* run-time initialization ********/
  608. void init_process(void)
  609. {
  610.   tc_process = add_new_type(&process_type);
  611.   init_proc_table();
  612.  
  613.   add_new_primitive("run-process", tc_subr_3, run_process);    /* + */
  614.   add_new_primitive("run-sync", tc_subr_3, run_sync);    /* + */
  615.   add_new_primitive("process?", tc_subr_1, processp);    /* + */
  616.   add_new_primitive("process-alive?", tc_subr_1,  process_alivep);  /* + */
  617.   add_new_primitive("process-input-info", tc_subr_1, process_input_info);  /* + */
  618.   add_new_primitive("process-output-info", tc_subr_1, process_output_info);  /* + */
  619.   add_new_primitive("process-error-info", tc_subr_1, process_error_info);  /* + */
  620.   add_new_primitive("process-command", tc_subr_1, process_command);    /* + */
  621.   add_new_primitive("process-pid", tc_subr_1, process_pid);    /* + */
  622.   add_new_primitive("process-input", tc_subr_1, process_input);    /* + */
  623.   add_new_primitive("process-output", tc_subr_1, process_output);  /* + */
  624.   add_new_primitive("process-error", tc_subr_1, process_error);    /* + */  
  625.   add_new_primitive("process-kill", tc_subr_1,process_kill);    /* + */
  626.   add_new_primitive("process-list", tc_subr_0,process_list);    /* + */
  627.  
  628. }
  629.